// File:    testbloat.c++
// Author:  (c) Miles Sabin, 1997
//          cathexis@mistral.co.uk
//          miles@mistral.co.uk
// Date:    17/02/97
// Purpose: Test ANSI container template bloat

// Compiling with -DNUM_MAPS=<n> with n from 1..8 will generate
// code for 1..8 distinct instantiations of map<K, T, Compare>
//
// Compile with -DANSI_HEADERS if you have headers of the form
// <list>, <map> etc., leave undefined if your headers are
// HP STL style, ie. "list.h", "map.h". If neither of these, then
// you'll have to fiddle with the #includes below (a single
// #include "stl.h" may do the trick).

// No output produced ... maps are simply created, and exercised
// a bit to ensure that some map<K, T, Compare> mfns are
// instantiated and emitted.
//
// This has been tested with:
//
//   1. Acorn C/C++ (CFront based) and CathLibCPP (my implementation
//        of the draft ANSI standard library), emulated exception
//        handling and RTTI enabled, linked against the Acorn RiscOS
//        shared C library.
//
//   2. Acorn RiscOS port of gcc 2.7.2 and libg++ (HP STL derived)
//       compiled with exception handling and RTTI disabled, and
//       linked against the Acorn RiscOS shared C library.
//
// The underlying implementation of both the libg++/HP STL and
// CathLibCPP map<> template is very similar (red-black tree,
// implemented from Cormen et. al. _An_Introduction_to_Algorithms_).
//
// The important metric is the increment in code size as the argument
// to -DNUM_MAPS is increased.
//
//            |    Acorn C/C++, CathlibCPP      |         gcc 2.7.2, libg++         |
//            |                                 |                                   |
//   NUM_MAPS |  code size (bytes)   increment  |   code size (bytes)   increment   |
//            |                                 |                                   |
//      1     |         13852           ----    |          13832           ----     |
//      2     |         14864           1012    |          21708           7876     |
//      3     |         15876           1012    |          29600           7892     |
//      4     |         16888           1012    |          37492           7892     |
//      5     |         17900           1012    |          45384           7892     |
//      6     |         18912           1012    |          53280           7896     |
//      7     |         19924           1012    |          61172           7892     |
//      8     |         20936           1012    |          69064           7892     |
//
//
// Note: with CathLibCPP some of the 1012 byte increment would
// be shared amongst all of,
//
//   deque<SomeClass>
//   list<SomeClass>
//   map<K, SomeClass, Compare>
//   map<SomeClass, T, Compare>
//   multimap<K, SomeClass, Compare>
//   multimap<SomeClass, T, Compare>
//   set<SomeClass, Compare>
//   multiset<SomeClass, Compare>
//   vector<SomeClass>
//
//   any other template classes that use CathLibCPP's
//   template hoisting mechanism
//
// for any given template argument SomeClass, so the results for
// CathLibCPP are even better in practice than they appear on paper.


#ifdef ANSI_HEADERS
#include <functional>
#include <map>
#else
#include "functional.h"
#include "map.h"
#endif

// These #includes only apply to Acorn C/C++ and CathLibCPP.
// Acorn CFront can't automatically instantiate template
// code in .c++ files.
#ifdef CATHLIBCPP
#include "map.c++"
#include "hoistbp.c++"
#include "hoistctdt.c++"
#endif


// Macro MAKE_A_MAP
//   Declare and define a class for instertion into a map.
//   Instantiate map<int, Class_n, less<int> >

#define MAKE_A_MAP(n)                                                  \
class Class_ ## n                                                      \
{                                                                      \
  friend bool operator==(Class_ ## n const& x, Class_ ## n const& y);  \
  friend bool operator< (Class_ ## n const& x, Class_ ## n const& y);  \
                                                                       \
  public:                                                              \
                                                                       \
    Class_ ## n (int i = 0);                                           \
    ~Class_ ## n ();                                                   \
                                                                       \
  private:                                                             \
                                                                       \
    int i_;                                                            \
};                                                                     \
                                                                       \
Class_ ## n::Class_ ## n (int i)                                       \
  : i_(i)                                                              \
  {}                                                                   \
                                                                       \
Class_ ## n::~Class_ ## n ()                                           \
  {}                                                                   \
                                                                       \
inline bool operator==(Class_ ## n const& x, Class_ ## n const& y)     \
  { return x.i_ == y.i_; }                                             \
                                                                       \
inline bool operator< (Class_ ## n const& x, Class_ ## n const& y)     \
  { return x.i_ < y.i_; }                                              \
                                                                       \
inline void destroy(Class_ ## n * p)                                   \
{                                                                      \
  p->~Class_ ## n ();                                                  \
}                                                                      \
                                                                       \
typedef map<int, Class_ ## n, less<int> > map_ ## n;


// Macro EXERCISE_A_MAP
//   Perform some simple map operations. Ensures that map insertion
//   and deletion ops are instantiated and emitted.

#define EXERCISE_A_MAP(n)                                              \
{                                                                      \
  map_ ## n a_map;                                                     \
                                                                       \
  for(int i = 0; i < 16; ++i)                                          \
    a_map[i] = Class_ ## n (i);                                        \
                                                                       \
  a_map.erase(a_map.begin());                                          \
}

MAKE_A_MAP(0);

#if NUM_MAPS > 1
MAKE_A_MAP(1)
#endif

#if NUM_MAPS > 2
MAKE_A_MAP(2)
#endif

#if NUM_MAPS > 3
MAKE_A_MAP(3)
#endif

#if NUM_MAPS > 4
MAKE_A_MAP(4)
#endif

#if NUM_MAPS > 5
MAKE_A_MAP(5)
#endif

#if NUM_MAPS > 6
MAKE_A_MAP(6)
#endif

#if NUM_MAPS > 7
MAKE_A_MAP(7)
#endif


int main()
{
  EXERCISE_A_MAP(0);

#if NUM_MAPS > 1
  EXERCISE_A_MAP(1)
#endif

#if NUM_MAPS > 2
  EXERCISE_A_MAP(2)
#endif

#if NUM_MAPS > 3
  EXERCISE_A_MAP(3)
#endif

#if NUM_MAPS > 4
  EXERCISE_A_MAP(4)
#endif

#if NUM_MAPS > 5
  EXERCISE_A_MAP(5)
#endif

#if NUM_MAPS > 6
  EXERCISE_A_MAP(6)
#endif

#if NUM_MAPS > 7
  EXERCISE_A_MAP(7)
#endif

  return 0;
}
